import lodash from 'lodash'
import { Controller, Get, Put, Post, Patch, Delete, Query, Body, UseGuards, HttpStatus } from '@nestjs/common'
import { Throttle, seconds } from '@nestjs/throttler'
import { AuthUserGuard } from '@app/guards/auth-user.guard'
import { PermissionPipe } from '@app/pipes/permission.pipe'
import { ExposePipe } from '@app/pipes/expose.pipe'
import { SortType } from '@app/constants/biz.constant'
import { Responser } from '@app/decorators/responser.decorator'
import { QueryParams, QueryParamsResult } from '@app/decorators/queryparams.decorator'
import { PaginateResult, PaginateQuery, PaginateOptions } from '@app/utils/paginate'
import { CommentPaginateQueryDTO, CommentsDTO, CommentsStateDTO } from './comment.dto'
import { CommentService } from './comment.service'
import { Comment, CommentBase } from './comment.model'

@Controller('comment')
export class CommentController {
  constructor(private readonly commentService: CommentService) { }

  @Get()
  @UseGuards(AuthUserGuard)
  @Responser.paginate()
  @Responser.handle('获取评论列表')
  getComments(
    @Query(PermissionPipe, ExposePipe) query: CommentPaginateQueryDTO,
    @QueryParams() { isUnauthenticated }: QueryParamsResult
  ): Promise<PaginateResult<Comment>> {
    const { sort, page, per_page, ...filters } = query
    const paginateQuery: PaginateQuery<Comment> = {}
    const paginateOptions: PaginateOptions = { page, perPage: per_page }

    // sort
    if (!lodash.isUndefined(sort)) {
      if (sort === SortType.Hottest) {
        paginateOptions.sort = { likes: SortType.Desc }
      } else {
        paginateOptions.dateSort = sort
      }
    }

    // state
    if (!lodash.isUndefined(filters.state)) {
      paginateQuery.state = filters.state
    }

    // post ID
    if (!lodash.isUndefined(filters.post_id)) {
      paginateQuery.post_id = filters.post_id
    }

    // search
    if (filters.keyword) {
      const trimmed = lodash.trim(filters.keyword)
      const keywordRegExp = new RegExp(trimmed, 'i')
      paginateQuery.$or = [
        { content: keywordRegExp },
        { 'author.name': keywordRegExp },
        { 'author.email': keywordRegExp },
      ]
    }

    return this.commentService.paginater(paginateQuery, paginateOptions, isUnauthenticated)
  }

  @Post()
  @Throttle({ default: { ttl: seconds(30), limit: 6 } })
  @Responser.handle('创建评论')
  createComment(@Body() comment: CommentBase, @QueryParams() { visitor }: QueryParamsResult): Promise<Comment> {
    return comment.author.email
      ? this.commentService.createFormClient(comment, visitor)
      : Promise.reject(`author email should not be empty`)
  }

  @Patch()
  @UseGuards(AuthUserGuard)
  @Responser.handle('更新评论')
  patchComments(@QueryParams() { visitor }: QueryParamsResult, @Body() body: CommentsStateDTO) {
    return this.commentService.batchPatchState(body, visitor.referer)
  }

  @Delete()
  @UseGuards(AuthUserGuard)
  @Responser.handle('删除评论')
  delComments(@Body() body: CommentsDTO) {
    return this.commentService.batchDelete(body.comment_ids, body.post_ids)
  }

  @Get(':id')
  @UseGuards(AuthUserGuard)
  @Responser.handle({ message: 'Get comment detail', error: HttpStatus.NOT_FOUND })
  getComment(@QueryParams() { params }: QueryParamsResult): Promise<Comment> {
    return this.commentService.getDetailByObjectID(params.id).then((comment) => {
      return comment ? comment : Promise.reject('Comment not found')
    })
  }

  @Put(':id')
  @UseGuards(AuthUserGuard)
  @Responser.handle('Update comment')
  putComment(@QueryParams() { params, visitor }: QueryParamsResult, @Body() comment: Comment): Promise<Comment> {
    return this.commentService.update(params.id, comment, visitor.referer)
  }

  @Put(':id/ip_location')
  @UseGuards(AuthUserGuard)
  @Responser.handle('Update comment IP location')
  putCommentIPLocation(@QueryParams() { params }: QueryParamsResult) {
    return this.commentService.reviseIPLocation(params.id)
  }

  @Delete(':id')
  @UseGuards(AuthUserGuard)
  @Responser.handle('Delete comment')
  delComment(@QueryParams() { params }: QueryParamsResult) {
    return this.commentService.delete(params.id)
  }
}
